package expression

import (
	"gitee.com/huanminabc/go-utils/code_analysis"
	"gitee.com/huanminabc/go-utils/common"
	"strconv"
)

func CalculateCore(tokens []code_analysis.Token) string {
	//先去掉字符串
	tokens, str := removeString(tokens)
	if str != "" { //如果有字符串,那么直接返回,这种情况表示字符串不是数字,那么就将全部的值拼接起来
		return str
	}
	//先去掉括号
	bracket := removeBracket(tokens)
	//计算表达式
	expression := calculateExpression(bracket)
	return expression
}

// 计算表达式
func calculateExpression(tokens []code_analysis.Token) string {
	//如果长度是1,并且是constant,那么直接返回
	if len(tokens) == 1 && tokens[0].Type == code_analysis.CONSTANT {
		return tokens[0].Value
	}
	//如果长度为2但是结尾的是;那么就跳过
	if len(tokens) == 2 && tokens[0].Type == code_analysis.CONSTANT && tokens[1].Value == ";" {
		return tokens[0].Value
	}

	//获取全部的运算符个数OPERATOR
	var operatorCount = 0
	for i := 0; i < len(tokens); i++ {
		if tokens[i].Type == code_analysis.OPERATOR {
			operatorCount++
		}
	}

	priority := qperatorPriority(tokens) //运算符优先级
	if priority != nil && len(priority) != 0 {
		var priorityLen = len(priority)
		var index = 0
		for i := 0; i < len(tokens); i++ {
			//找到第一个运算符
			if tokens[i].Type == code_analysis.OPERATOR && index < priorityLen && tokens[i].Value == priority[index] {
				//找到第一个运算符,然后找到左右两边的值
				left := tokens[i-1].Value
				right := tokens[i+1].Value
				//判断左右两边的值是否是数字
				if !(common.IsNumber(left) && common.IsNumber(right)) {
					panic("表达式中的值不能是非数值的存在 " + left + " " + tokens[i].Value + " " + right)
				}
				//计算
				calculate := calculate(left, right, tokens[i].Value)
				tokens[i-1].Value = calculate
				//删除右边的值
				tokens = append(tokens[:i], tokens[i+2:]...)
				//重新计算
				i = 0
				index++ //下一个运算符
				operatorCount--
			}
		}
		//如果operatorCount为0,那么说明只有一个值,直接返回,否则继续计算
		if operatorCount == 0 {
			return tokens[0].Value
		}

	}

	//逻辑运算
	//1.先计算单目运算符
	tokens = unaryOperation(tokens)
	//2.取出优先级
	operatorPriority := logicalOperatorPriority(tokens)
	//3.计算逻辑运算符
	if operatorPriority != nil && len(operatorPriority) != 0 {
		var operatorPriorityLen = len(operatorPriority)
		var index = 0
		for i := 0; i < len(tokens); i++ {
			//找到第一个运算符
			if tokens[i].Type == code_analysis.OPERATOR && index < operatorPriorityLen && tokens[i].Value == operatorPriority[index] {
				//找到第一个运算符,然后找到左右两边的值
				left := tokens[i-1].Value
				right := tokens[i+1].Value
				//计算
				calculate := logicalOperation(left, right, tokens[i].Value)
				tokens[i-1].Value = calculate
				//删除右边的值
				tokens = append(tokens[:i], tokens[i+2:]...)
				//重新计算
				i = 0
				index++ //下一个运算符
				operatorCount--
			}
		}
		//如果operatorCount为0,那么说明只有一个值,直接返回,否则继续计算
		if operatorCount == 0 {
			return tokens[0].Value
		} else {
			panic("未处理完毕全部的运算符")
		}
	}
	panic("表达式中没有运算符")
}

// 去掉括号
func removeBracket(tokens []code_analysis.Token) []code_analysis.Token {
	//找到第一个右括号,然后在向前找左括号,计算括号中的值,然后替换
	for i := len(tokens) - 1; i >= 0; i-- {
		if tokens[i].Type == code_analysis.SYMBOL && tokens[i].Value == "(" {
			//向前找右括号
			for j := i; j < len(tokens); j++ {
				if tokens[j].Type == code_analysis.SYMBOL && tokens[j].Value == ")" {
					//找到括号中的值
					bracketTokens := tokens[i+1 : j]
					var newTokens = make([]code_analysis.Token, len(bracketTokens))
					copy(newTokens, bracketTokens) //复制避免影响原来的
					//计算括号中的值
					bracketValue := calculateExpression(newTokens)
					//替换
					tokens[i].Value = bracketValue
					tokens[i].Type = code_analysis.CONSTANT
					tokens[i].ValueType = code_analysis.IsDataType(bracketValue)
					//删除括号中的值
					tokens = append(tokens[:i+1], tokens[j+1:]...)
					break
				}
			}
		}
	}
	return tokens

}

// 去掉字符串, 字符串基本上只有'和"两种 ,那么将字符串相加然后转换为数字,如果不是数字,那么就报错
func removeString(tokens []code_analysis.Token) ([]code_analysis.Token, string) {
	//找到第一个字符串,然后在向前找右第一个字符串,计算字符串中的值,然后替换
	for i := 0; i < len(tokens); i++ {
		if i+2 < len(tokens) && tokens[i].Type == code_analysis.CONSTANT && tokens[i].ValueType == code_analysis.STRING &&
			tokens[i+1].Type == code_analysis.OPERATOR && tokens[i+1].Value == "+" &&
			(tokens[i+2].ValueType == code_analysis.STRING || tokens[i+2].ValueType == code_analysis.CHAR) {
			//去掉"
			value := tokens[i].Value
			//判断开头和结尾是否是"
			if value[0] == '"' && value[len(value)-1] == '"' {
				value = value[1 : len(value)-1]
			}
			value2 := tokens[i+2].Value[1 : len(tokens[i+2].Value)-1]
			//这种情况可以直接合并
			tokens[i].Value = "\"" + value + value2 + "\""
			//删除后面的
			tokens = append(tokens[:i+1], tokens[i+3:]...)
			i--
			continue
		}
		//判断是字符
		if tokens[i].Type == code_analysis.CONSTANT && tokens[i].ValueType == code_analysis.CHAR {
			//去掉'
			str := tokens[i].Value[1 : len(tokens[i].Value)-1]
			//转换为数字
			u := uint(str[0]) //转换为数字
			//替换
			tokens[i].Value = strconv.Itoa(int(u))
			tokens[i].ValueType = code_analysis.IsDataType(tokens[i].Value)
		}

	}

	return tokens, ""

}

// 逻辑运算符优先级
func logicalOperatorPriority(tokens []code_analysis.Token) []string {
	var operatorList []code_analysis.Token
	var len_ = len(tokens)
	for i := 0; i < len_; i++ {
		if tokens[i].Type == code_analysis.OPERATOR && (tokens[i].Value == "==" || tokens[i].Value == "!=" ||
			tokens[i].Value == ">" || tokens[i].Value == "<" || tokens[i].Value == ">=" ||
			tokens[i].Value == "<=" || tokens[i].Value == "&&" || tokens[i].Value == "||") {
			operatorList = append(operatorList, tokens[i])
		}
	}
	//排序  ==,!=,>,<,>=,<=,&&,||
	var operatorSort1 []string
	var operatorSort2 []string
	var len__ = len(operatorList)
	for i := 0; i < len__; i++ {
		// 1. ==,!=,>,<,>=,<=
		if operatorList[i].Value == "==" || operatorList[i].Value == "!=" || operatorList[i].Value == ">" ||
			operatorList[i].Value == "<" || operatorList[i].Value == ">=" || operatorList[i].Value == "<=" {
			operatorSort1 = append(operatorSort1, operatorList[i].Value)
			continue
		}
		// 2. &&,||
		if operatorList[i].Value == "&&" || operatorList[i].Value == "||" {
			operatorSort2 = append(operatorSort2, operatorList[i].Value)
			continue
		}

	}
	operatorSort := append(operatorSort1, operatorSort2...)
	return operatorSort

}

// 运算符优先级,把token内部的全部运算符找出来,然后按照优先级排序返回列表
func qperatorPriority(tokens []code_analysis.Token) []string {
	var operatorList []code_analysis.Token
	var len_ = len(tokens)
	for i := 0; i < len_; i++ {
		if tokens[i].Type == code_analysis.OPERATOR {
			operatorList = append(operatorList, tokens[i])
		}
	}
	//排序  +,-,*,/,%,^

	var operatorSort1 []string
	var operatorSort2 []string
	var len__ = len(operatorList)
	for i := 0; i < len__; i++ {
		// 1. * / % ^
		if operatorList[i].Value == "*" || operatorList[i].Value == "/" || operatorList[i].Value == "%" || operatorList[i].Value == "^" {
			operatorSort1 = append(operatorSort1, operatorList[i].Value)
			continue
		}
		// 2. + -
		if operatorList[i].Value == "+" || operatorList[i].Value == "-" {
			operatorSort2 = append(operatorSort2, operatorList[i].Value)
			continue
		}

	}
	operatorSort := append(operatorSort1, operatorSort2...)
	return operatorSort
}

// 单目运算符
func unaryOperation(tokens []code_analysis.Token) []code_analysis.Token {
	//先找到!的位置
	for i := 0; i < len(tokens); i++ {
		if tokens[i].Type == code_analysis.OPERATOR && tokens[i].Value == "!" {
			//找到!的位置,然后找到右边的值
			right := tokens[i+1].Value
			//判断右边的值,如果是数字,判断是否是0,如果是0,则返回1,否则返回0
			if common.IsNumber(right) {
				if right == "0" {
					tokens[i+1].Value = "1"
				} else {
					tokens[i+1].Value = "0"
				}
				//删除!
				tokens = append(tokens[:i], tokens[i+1:]...)
				break
			}
			//判断是布尔
			if right == "true" || right == "false" {
				if right == "true" {
					tokens[i+1].Value = "false"
				} else {
					tokens[i+1].Value = "true"
				}
				//删除!
				tokens = append(tokens[:i], tokens[i+1:]...)
				break
			}
		}
	}
	return tokens
}

// 逻辑运算 ==,!=,>,<,>=,<=,&&,||
func logicalOperation(left string, right string, operator string) string {

	//如果operator是&&或者||那么就需要转换为布尔
	if operator == "&&" || operator == "or" {
		//判断是否是数字如果是那么将非0的数字转换为true,0转换为false
		if common.IsNumber(left) {
			if left == "0" {
				left = "false"
			} else {
				left = "true"
			}
		}
		if common.IsNumber(right) {
			if right == "0" {
				right = "false"
			} else {
				right = "true"
			}

		}
		//判断是否是布尔
		if left != "true" && left != "false" {
			panic(left + operator + right + "左侧的值不是布尔类型或者数字类型")
		}
		if right != "true" && right != "false" {
			panic(left + operator + right + "右侧的值不是布尔类型或者数字类型")
		}
	}
	//计算
	switch operator {
	case "==":
		if left == right {
			return "true"
		} else {
			return "false"
		}
	case "!=":
		if left != right {
			return "true"
		} else {
			return "false"
		}
	case ">":
		if left > right {
			return "true"
		} else {
			return "false"
		}
	case "<":
		if left < right {
			return "true"
		} else {
			return "false"
		}
	case ">=":
		if left >= right {
			return "true"
		} else {
			return "false"
		}
	case "<=":
		if left <= right {
			return "true"
		} else {
			return "false"
		}
	case "&&":
		if left == "true" && right == "true" {
			return "true"
		} else {
			return "false"
		}
	case "||":
		if left == "true" || right == "true" {
			return "true"
		} else {
			return "false"
		}

	default:
		panic("不支持的逻辑运算符:" + operator)
	}
}

// 不支持字符串相加 ,只支持数字相加
func calculate(left string, right string, operator string) string {
	//判断是否全部是数字
	var isInt = common.IsInt(left) && common.IsInt(right)
	//转换为数字
	leftInt := common.StringToFloat64(left)
	rightInt := common.StringToFloat64(right)
	//计算
	switch operator {
	case "*":
		//判断是否是整数
		if !isInt {
			return strconv.FormatFloat(leftInt*rightInt, 'f', -1, 64)
		} else {
			return strconv.FormatInt(int64(leftInt*rightInt), 10)
		}
	case "/":
		//判断是否是整数
		if !isInt {
			return strconv.FormatFloat(leftInt/rightInt, 'f', -1, 64)
		} else {
			return strconv.FormatInt(int64(leftInt/rightInt), 10)
		}
	case "%":
		//判断是否是整数
		if !isInt {
			return strconv.FormatFloat(float64(int64(leftInt)%int64(rightInt)), 'f', -1, 64)
		} else {
			return strconv.FormatInt(int64(leftInt)%int64(rightInt), 10)
		}
	case "^":
		//判断是否是整数
		if !isInt {
			return strconv.FormatFloat(float64(int64(leftInt)^int64(rightInt)), 'f', -1, 64)
		} else {
			return strconv.FormatInt(int64(leftInt)^int64(rightInt), 10)
		}
	case "+":
		//判断是否是整数
		if !isInt {
			return strconv.FormatFloat(leftInt+rightInt, 'f', -1, 64)
		} else {
			return strconv.FormatInt(int64(leftInt+rightInt), 10)
		}
	case "-":
		//判断是否是整数
		if !isInt {
			return strconv.FormatFloat(leftInt-rightInt, 'f', -1, 64)
		} else {
			return strconv.FormatInt(int64(leftInt-rightInt), 10)
		}
	default:
		panic("不支持的运算符:" + operator)
	}
}
